package com.wangyu.utils;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.ArrayUtils;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * 对象序列化反序列化
 *
 * @author Mr.Wang
 */
public class ObjectParser {

    /**
     * json字符串转换为指定类型的对象
     *
     * @param json json字符串
     * @param type 指定的类型class
     * @param <T>  类型
     * @return 对象
     */
    public static <T> T parse(String json, Class<T> type) {
        return JacksonUtil.fromJson(json, type);
    }

    /**
     * 使用TypeReference的方式转换bean，效率可能低于class引用
     *
     * @param json json字符串
     * @param <T>  泛型
     * @return 对象
     */
    public static <T> T parse(String json) {
        return JacksonUtil.fromJson(json);
    }

    /**
     * json字符串转换为裸List
     *
     * @param <T>   泛型
     * @param json  json字符串
     * @param clazz 类
     * @return list对象
     */
    public static <T> List<T> parseList(String json, Class<T> clazz) {
        return JacksonUtil.json2List(json, clazz);
    }

    /**
     * json字符串转换为裸List
     *
     * @param <T>  泛型
     * @param json json字符串
     * @return list对象
     */
    public static <T> List<T> parseList(String json) {
        return JacksonUtil.json2List(json);
    }

    /**
     * json字符串转换为Map
     *
     * @param json json字符串
     * @param <K>  键类型
     * @param <V>  值类型
     * @return Map
     */
    public static <K, V> Map<K, V> parseMap(String json) {
        return JacksonUtil.json2Map(json);
    }

    /**
     * 对象转换为JSON字符串
     *
     * @param object 对象
     * @param <T>    泛型
     * @return 字符串
     */
    public static <T> String toJSON(T object) {
        return JacksonUtil.toJson(object);
    }

    /**
     * map转bean
     *
     * @param objectMap map
     * @param tClass    class
     * @param <T>       泛型
     * @return 结果bean
     */
    @SuppressWarnings("unchecked")
    public static <T> T mapToBean(Map<String, Object> objectMap, Class<T> tClass) {
        // 过滤map的integer转为long
//        fixMapValue(objectMap);
        try {
            T bean = tClass.newInstance();
            BeanUtils.populate(bean, objectMap);
            return bean;
        } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * bean转换map
     * 特性：支持过滤空值，降低带宽耗费
     *
     * @param object javaBean
     * @param <T>    泛型
     * @return 处理后的Map
     */
    @SuppressWarnings("unchecked")
    public static <T> Map<String, Object> beanToMap(T object) {
        if (object == null) {
            return null;
        }
        if (object instanceof Map) {
            return (Map<String, Object>) object;
        }
        Map<String, Object> map = new HashMap<>();
        // 获取javaBean属性
        getBeanInfoAndThen(object, beanInfo -> {
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            if (ArrayUtils.isNotEmpty(propertyDescriptors)) {
                Arrays.stream(propertyDescriptors).forEach(propertyDescriptor -> {
                    // javaBean属性名
                    String propertyName = propertyDescriptor.getName();
                    if (!"class".equals(propertyName)) {
                        try {
                            Object value = propertyDescriptor.getReadMethod().invoke(object);
                            // 过滤空值，节约带宽
                            if (value != null) {
                                // javaBean属性值
                                map.put(propertyName, value);
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        });
        return map;
    }

    /**
     * 批量转换Map
     *
     * @param beans list
     * @param <T>   泛型
     * @return 转换后的list
     */
    public static <T> List<Map<String, Object>> beansToMaps(List<T> beans) {
        return beans.stream().map(ObjectParser::beanToMap).collect(Collectors.toList());
    }

    /**
     * 得到beanInfo，然后执行consumer
     *
     * @param javaBean bean
     * @param consumer 消费函数
     */
    private static void getBeanInfoAndThen(Object javaBean, Consumer<BeanInfo> consumer) {
        try {
            consumer.accept(Introspector.getBeanInfo(javaBean.getClass()));
        } catch (IntrospectionException e) {
            e.printStackTrace();
        }
    }

    /**
     * 修复map
     *
     * @param map map
     */
    private static void fixMapValue(Map<String, Object> map) {
        map.forEach((key, value) -> {
            if (value instanceof Integer) {
                map.put(key, Long.valueOf(String.valueOf(value)));
            }
        });
    }
}
